package com.sec.android.app.myfiles.module.abstraction;

import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.DragEvent;
import android.view.PointerIcon;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.MeasureSpec;
import android.view.View.OnDragListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.facade.MyFilesFacade;
import com.sec.android.app.myfiles.facade.cmd.SpinnerProgressCmd;
import com.sec.android.app.myfiles.feature.DragAndDropMgr;
import com.sec.android.app.myfiles.feature.KnoxMgr;
import com.sec.android.app.myfiles.fragment.AbsMyFilesFragment;
import com.sec.android.app.myfiles.info.AppConstants;
import com.sec.android.app.myfiles.info.AppFeatures;
import com.sec.android.app.myfiles.info.MediaFile;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.module.local.foldertree.FolderTreeRecord;
import com.sec.android.app.myfiles.module.shortcut.ShortcutUtils;
import com.sec.android.app.myfiles.navigation.NavigationInfo;
import com.sec.android.app.myfiles.navigation.NavigationManager;
import com.sec.android.app.myfiles.operation.FileOperator;
import com.sec.android.app.myfiles.operation.ProgressListener;
import com.sec.android.app.myfiles.thumbnail.ThumbnailMgr;
import com.sec.android.app.myfiles.util.FileUtils;
import com.sec.android.app.myfiles.util.PreferenceUtils;
import com.sec.android.app.myfiles.util.StorageMonitor;
import com.sec.android.app.myfiles.util.UiUtils;
import com.sec.android.app.myfiles.widget.listview.AbsListViewImp;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;

public class AbsDragAndDrop implements OnDragListener, ProgressListener {
    private final int DRAG_VIEW = 1;
    private final int DRAG_AND_DROP_VIEW = 2;
    private static SparseArray<View> sDragAndDropMap = new SparseArray<>();
    private View mDragView;
    private View mDragAndDropView;

    private static FileRecord sPressedFile = null;
    private static int sCheckedItemCount = 0;
    private static int sDragWidth = 0;
    private static int sDragHeight = 0;

    private final BlockingQueue<Runnable> mLoadQueue = new LinkedBlockingQueue<>();
    private final ThreadPoolExecutor mLoadThreadPool = new ThreadPoolExecutor(
            AppConstants.NUMBER_OF_THREADS, AppConstants.NUMBER_OF_THREADS,
            AppConstants.IDLE_THREAD_KEEP_ALIVE_TIME, AppConstants.IDLE_THREAD_KEEP_ALIVE_TIME_UNIT,
            mLoadQueue);

    protected AbsListViewImp mListViewImp;
    protected Context mContext;
    protected AbsMyFilesFragment mFragment;
    protected boolean mNeedChangePointer = false;
    protected boolean mNoDrop = false;
    private boolean mDragStart;
    protected int mPrevPosition = AppConstants.UNDEFINED;
    private boolean mIsPointerGuideEnable = false;
    private DragUpdateThread mDragUpdateThread;
    private BroadcastReceiver mMoveToKnoxReceiver = null;

    public AbsDragAndDrop(AbsMyFilesFragment fragment, AbsListViewImp listViewImp) {
        mListViewImp = listViewImp;
        mContext = fragment.context();
        mFragment = fragment;
        mDragStart = false;
    }

    @Override
    public boolean onDrag(View view, DragEvent event) {
        boolean bRet = false;
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();
        AbsListView listView = null;

        int position = AppConstants.UNDEFINED;
        if (view instanceof AbsListView) {
            listView = (AbsListView) view;
            position = listView.pointToPosition(x, y);
        }

        switch (action) {
            case DragEvent.ACTION_DRAG_STARTED:
                bRet = handleActionDragStarted(event, listView);
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                bRet = handleActionDragEntered(view);
                break;
            case DragEvent.ACTION_DRAG_LOCATION:
                bRet = handleActionDragLocation(view, event, listView, position, y);
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                handleActionDragExited(view, position);
                break;
            case DragEvent.ACTION_DRAG_ENDED:
                handleActionDragEnded(view, event, listView, position);
                break;
            case DragEvent.ACTION_DROP:
                bRet = handleActionDrop(view, event, position);
                break;
            default:
                break;
        }
        return bRet;
    }

    protected boolean handleActionDragStarted(DragEvent event, AbsListView listView) {
        Log.a(this, "ACTION_DRAG_STARTED");
        registerMoveToKnoxReceiver();
        if (event.getClipDescription() != null) {
            if (!TextUtils.isEmpty(event.getClipDescription().getLabel())) {
                UiUtils.sendLocalBroadcastIntent(mContext, AppConstants.MYFILES_ACTION_DRAG_AND_DROP_START, -1);
            }
        }
        mNoDrop = false;
        return true;
    }

    protected boolean handleActionDragEntered(View view) {
        Log.a(this, "ACTION_DRAG_ENTERED");
        return true;
    }

    protected boolean handleActionDragLocation(View view, DragEvent event, AbsListView listView, int position, int y) {
        Log.a(this, "ACTION_DRAG_LOCATION");
        if (listView != null) {
            View firstChild = listView.getChildAt(0);
            if (firstChild != null) {
                int listItemHeight = firstChild.getHeight();
                int lowerBound = listView.getHeight() - listItemHeight;
                if (y > lowerBound) {
                    if (listView.getLastVisiblePosition() <= listView.getCount() - 1) {
                        listView.smoothScrollBy(listItemHeight, 500);
                    }
                } else if (y < listItemHeight) {
                    if (listView.getFirstVisiblePosition() != 0 || firstChild.getTop() < listView.getPaddingTop()) {
                        listView.smoothScrollBy(-listItemHeight, 500);
                    }
                }
                if (position == AppConstants.UNDEFINED) {
                    clearBackground(position, view);
                } else {
                    doDrag(position);
                }
                FileRecord dstFile = getSelectFolder(position);
                if (dstFile instanceof FolderTreeRecord ||
                        (dstFile != null && dstFile.isDirectory() && dstFile.getParent() != null)) {
                    addPointerGuide(position, true);
                } else {
                    addPointerGuide(position, false);
                }
                mPrevPosition = position;
            }
        } else { // empty view
            mNeedChangePointer = true;
            mNoDrop = false;
            NavigationInfo curInfo = mFragment.getNavigationInfo();
            if (curInfo != null) {
                FileRecord curRecord = curInfo.getCurRecord();
                if (curRecord != null) {
                    mNoDrop = StorageMonitor.isRemovedExtSDCard(curRecord.getFullPath())
                            || FileRecord.StorageType.Blank.equals(curRecord.getStorageType())
                            || !DragAndDropMgr.canDrop(mContext, event.getClipDescription());
                }
            }
        }

        updateMousePointerIcon(event);
        return true;
    }

    protected void updateMousePointerIcon(DragEvent event) {
        if (mNeedChangePointer) {
            UiUtils.setMousePointerIcon(mContext, mNoDrop ? PointerIcon.TYPE_NO_DROP : PointerIcon.TYPE_COPY);
        } else {
            UiUtils.setMousePointerIcon(mContext, DragAndDropMgr.canDrop(mContext, event.getClipDescription()) ? PointerIcon.TYPE_COPY : PointerIcon.TYPE_NO_DROP);
        }
        mNeedChangePointer = false;
    }

    protected void handleActionDragExited(View view, int position) {
        Log.a(this, "ACTION_EXITED");
        clearBackground(AppConstants.UNDEFINED, view);
        addPointerGuide(position, false);
        mPrevPosition = AppConstants.UNDEFINED;
        mNeedChangePointer = true;
        mNoDrop = false;
        UiUtils.setMousePointerIcon(mContext, PointerIcon.TYPE_GRABBING);
    }

    protected void handleActionDragEnded(View view, DragEvent event, AbsListView listView, int position) {
        unregisterMoveToKnoxReceiver();
        boolean ret = event.getResult();
        Log.a(this, "ACTION_ENDED - " + ret);
        clearBackground(AppConstants.UNDEFINED, view);
        UiUtils.sendLocalBroadcastIntent(mContext, AppConstants.MYFILES_ACTION_DRAG_AND_DROP_END, -1);
        addPointerGuide(position, false);
        mPrevPosition = AppConstants.UNDEFINED;
        mNeedChangePointer = false;
        mNoDrop = false;
        sDragAndDropMap.clear();
        UiUtils.setMousePointerIconToDefault();
    }

    protected boolean handleActionDrop(View view, DragEvent event, int position) {
        boolean bRet;
        Log.a(this, "ACTION_DROP - " + position);
        mFragment.getFileListActivity().requestDragAndDropPermissions(event);
        bRet = doDrop(event.getClipData(), position);
        if (bRet) {
            UiUtils.sendLocalBroadcastIntent(mContext, AppConstants.MYFILES_ACTION_DRAG_AND_DROP_FINISH, -1);
        }
        mNeedChangePointer = false;
        mNoDrop = false;
        return bRet;
    }

    private void registerMoveToKnoxReceiver() {
    }

    private void unregisterMoveToKnoxReceiver() {
        if (mMoveToKnoxReceiver != null) {
            mContext.unregisterReceiver(mMoveToKnoxReceiver);
            mMoveToKnoxReceiver = null;
        }
    }

    private static DragShadowBuilder sShadowBuilder;

    private void setUpDragShadow() {
        sShadowBuilder = new DragShadowBuilder(mDragAndDropView) {
            @Override
            public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
                int width = getView().getMeasuredWidth();
                int height = getView().getMeasuredHeight();
                shadowSize.set(width, height);
                shadowTouchPoint.set(width / 2, height / 2);
            }
        };
    }

    private void addPointerGuide(int position, boolean isShow) {
        mDragView = sDragAndDropMap.get(DRAG_VIEW);
        mDragAndDropView = sDragAndDropMap.get(DRAG_AND_DROP_VIEW);
        if (!AppFeatures.isKnoxDesktopMode() || (isShow && position == mPrevPosition) || (mDragAndDropView == null || mDragView == null)) {
            Log.d(this, "Return addPointerGuide() position: " + position + " mPrevPosition: " + mPrevPosition);
            return;
        }
        if (mDragUpdateThread != null) {
            mDragUpdateThread.setAlive(false);
        }
        mDragUpdateThread = new DragUpdateThread(position, isShow, true);
        mDragUpdateThread.start();
    }

    protected void clearBackground(int position, View view) {
        if (position != mPrevPosition) {
            if (view instanceof AbsListView) {
                AbsListView listView = (AbsListView) view;
                int firstPosition = listView.getFirstVisiblePosition();
                View prevPosition = listView.getChildAt(mPrevPosition - firstPosition);
                if (prevPosition != null && prevPosition.getTag() != view.getTag() && prevPosition.isEnabled()) {
                    prevPosition.setPressed(false);
                    restoreLastItemBackground(prevPosition);
                }
            }
        }
    }

    private void doDrag(int position) {
        AbsListView listView = mListViewImp.getListView();
        int firstPosition = listView.getFirstVisiblePosition();
        View view = listView.getChildAt(position - firstPosition);

        if (view != null && view.isEnabled()) {
            clearBackground(position, listView);
            ensureCurrentItemBackground(view);
            view.setPressed(true);
        } else {
            Log.d(this, "doDrag - view is null");
        }
    }

    public boolean isDragStart() {
        return mDragStart;
    }

    public void setDragStart(boolean dragStart) {
        mDragStart = dragStart;
    }

    private Drawable resizeForShadowIcon(Drawable drawable) {
        Bitmap b = ((BitmapDrawable) drawable).getBitmap();
        int size = mContext.getResources().getDimensionPixelSize(R.dimen.list_item_drag_and_drop_scaled_thumbnail_size);
        Bitmap bitmapResized = Bitmap.createScaledBitmap(b, size, size, false);
        return new BitmapDrawable(mContext.getResources(), bitmapResized);
    }

    private void setDragAndDropView() {
        ImageView thumbnailView = (ImageView) mDragAndDropView.findViewById(R.id.thumbnail);
        if (sPressedFile.isDirectory()) {
            Drawable drawable = MediaFile.getFileTypeDrawable(mContext, sPressedFile);
            thumbnailView.setImageDrawable(resizeForShadowIcon(drawable));
        } else {
            ImageView view = ThumbnailMgr.getInstance(mContext).loadThumbnail(sPressedFile, thumbnailView, thumbnailView);
            if (view == null) {
                Drawable drawable = mContext.getResources().getDrawable(MediaFile.getIcon(mContext, sPressedFile), null);
                thumbnailView.setImageDrawable(resizeForShadowIcon(drawable));
            }
        }

        TextView countView = (TextView) mDragAndDropView.findViewById(R.id.item_count);
        ImageView secondBg = (ImageView) mDragAndDropView.findViewById(R.id.thumbnail_second);
        ImageView lastBg = (ImageView) mDragAndDropView.findViewById(R.id.thumbnail_last);
        if (sCheckedItemCount == 1) {
            countView.setVisibility(View.INVISIBLE);
            secondBg.setVisibility(View.INVISIBLE);
            lastBg.setVisibility(View.INVISIBLE);
        } else {
            if (sCheckedItemCount == 2) {
                lastBg.setVisibility(View.INVISIBLE);
            }
            if (sCheckedItemCount >= 100) {
                ViewGroup.LayoutParams params = countView.getLayoutParams();
                params.width = ViewGroup.LayoutParams.MATCH_PARENT;
                countView.setLayoutParams(params);
            }
        }
        countView.setText(String.valueOf(sCheckedItemCount));
        Resources res = mContext.getResources();
        if (!AppFeatures.isKnoxDesktopMode()) {
            mDragAndDropView.measure(
                    MeasureSpec.makeMeasureSpec(res.getDimensionPixelSize(R.dimen.list_item_drag_and_drop_width), MeasureSpec.EXACTLY),
                    MeasureSpec.makeMeasureSpec(res.getDimensionPixelSize(R.dimen.list_item_drag_and_drop_height), MeasureSpec.EXACTLY));
        } else {
            mDragAndDropView.measure(sDragWidth, sDragHeight);
        }

        mDragAndDropView.layout(0, 0, mDragAndDropView.getMeasuredWidth(), mDragAndDropView.getMeasuredHeight());
    }

    private void updateDragAndDropView(boolean isGuide, FileRecord dstFile) {
        TextView guideView = (TextView) mDragAndDropView.findViewById(R.id.pointer_guide_detail);
        if (guideView != null) {
            if (isGuide && dstFile != null) {
                guideView.setVisibility(View.VISIBLE);
                String recordName = dstFile.getDisplayName(mContext);
                String guide = mContext.getString(R.string.copy_to) + " " + recordName;
                guideView.setText(guide);
            } else {
                guideView.setVisibility(View.INVISIBLE);
            }
        }

        setDragAndDropView();
    }

    public void doDrag(View view, ArrayList<FileRecord> selectedFiles, FileRecord pressedFile) {
        mDragView = view;
        sPressedFile = pressedFile;
        sCheckedItemCount = selectedFiles != null ? selectedFiles.size() : -1;
        mDragStart = true;

        if (view instanceof ViewGroup) {
            if (!AppFeatures.isKnoxDesktopMode()) {
                mDragAndDropView = mFragment.getActivity().getLayoutInflater().inflate(R.layout.drag_and_drop_shadow_common, (ViewGroup) view, false);
            } else {
                mDragAndDropView = mFragment.getActivity().getLayoutInflater().inflate(R.layout.drag_and_drop_shadow_tablet, (ViewGroup) view, false);
                Resources res = mContext.getResources();
                sDragWidth = MeasureSpec.makeMeasureSpec(res.getDimensionPixelSize(R.dimen.dexmode_list_item_drag_and_drop_width), MeasureSpec.EXACTLY);
                sDragHeight = MeasureSpec.makeMeasureSpec(res.getDimensionPixelSize(R.dimen.list_item_drag_and_drop_height), MeasureSpec.EXACTLY);
            }
        } else {
            return;
        }

        if (mDragAndDropView == null) {
            return;
        }

        sDragAndDropMap.put(DRAG_VIEW, mDragView);
        sDragAndDropMap.put(DRAG_AND_DROP_VIEW, mDragAndDropView);

        if (sCheckedItemCount > AppConstants.DRAG_DROP_SELECT_LIMIT_COUNT) {
            String msg = mContext.getResources().getString(R.string.max_num_selected_files, AppConstants.DRAG_DROP_SELECT_LIMIT_COUNT);
            Toast.makeText(mContext, msg, Toast.LENGTH_LONG).show();
            return;
        }

        if (sCheckedItemCount <= 0 || sPressedFile == null) {
            return;
        }

        setUpDragShadow();
        setDragAndDropView();

        mDragView.setDrawingCacheEnabled(true);

        ClipData data = prepareClipData(selectedFiles);
        mDragView.startDragAndDrop(data, sShadowBuilder, null, View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ | View.DRAG_FLAG_GLOBAL_URI_WRITE | View.DRAG_FLAG_OPAQUE);
        mDragView.setDrawingCacheEnabled(false);
    }

    private ClipData prepareClipData(ArrayList<FileRecord> selectedFiles) {
        if (selectedFiles == null) {
            return null;
        }

        ClipData data = null;
        String label;
        if (!selectedFiles.isEmpty()) {
            switch (selectedFiles.get(0).getStorageType()) {
                case Cloud:
                    label = DragAndDropMgr.DRAG_DROP_MYFILES_CLOUD;
                    break;
                default:
                    label = KnoxMgr.getInstance(mContext).isSecureFolder() ? DragAndDropMgr.DRAG_DROP_SOURCE_IS_SECURE_FOLDER : DragAndDropMgr.DRAG_DROP_MYFILES_LOCAL;
                    break;
            }
            data = getUriData(selectedFiles, label);
            if (AppFeatures.isKnoxDesktopMode() && selectedFiles.size() <= ShortcutUtils.SHORTCUT_LIMIT_COUNT_FOR_KNOX_DESKTOP && DragAndDropMgr.DRAG_DROP_MYFILES_LOCAL.equals(label)) {
                addIntentForDexShortcut(selectedFiles, data);
            }
            Log.e(this, "prepareClipData()  KnoxDesktopMode - " + AppFeatures.isKnoxDesktopMode() + "  count:" + selectedFiles.size());
        }
        return data;
    }

    private void addIntentForDexShortcut(ArrayList<FileRecord> selectedFiles, ClipData data) {
        ArrayList<Future<Intent>> intentFutures = new ArrayList<>();
        if (data != null) {
            for (final FileRecord record : selectedFiles) {
                intentFutures.add(mLoadThreadPool.submit(new Callable<Intent>() {
                    @Override
                    public Intent call() throws Exception {
                        return ShortcutUtils.getIntentForShortcut(mContext, record);
                    }
                }));
            }
            try {
                for (Future<Intent> intentFuture : intentFutures) {
                    data.addItem(new ClipData.Item(intentFuture.get()));
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

    private ClipData getUriData(ArrayList<FileRecord> selectedFiles, String label) {
        PersistableBundle bundle = new PersistableBundle();
        HashSet<String> mimeTypes = new HashSet<>();
        ArrayList<Future<Uri>> uriFutures = new ArrayList<>();
        String secLabel = "secdndfiletype";
        String[] mimeType = {ClipDescription.MIMETYPE_TEXT_URILIST};
        ClipDescription description = new ClipDescription(label, mimeType);

        for (final FileRecord record : selectedFiles) {
            if (record == null) {
                continue;
            }
            uriFutures.add(mLoadThreadPool.submit(new Callable<Uri>() {
                @Override
                public Uri call() throws Exception {
                    Uri uri = FileUtils.getPickUriByPath(mContext, record.getFullPath());
                    return uri == null ? record.getUri(mContext) : uri;
                }
            }));
            mimeTypes.add(record.getMimeType(mContext));
        }
        bundle.putStringArray(secLabel, mimeTypes.toArray(new String[0]));
        description.setExtras(bundle);
        ClipData ret = null;
        try {
            for (Future<Uri> uriFuture : uriFutures) {
                if (ret == null) {
                    ClipData.Item item = new ClipData.Item(uriFuture.get());
                    ret = new ClipData(description, item);
                } else {
                    ret.addItem(new ClipData.Item(uriFuture.get()));
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return ret;
    }

    public boolean doDrop(ClipData clipData, int dropPosition) {
        boolean bRet = false;
        FileRecord dstFile = getDstFile(dropPosition);

        if (clipData == null) {
            Log.e(this, "clipData is null");
            return false;
        }

        ClipData.Item item = clipData.getItemAt(0);
        Uri uri = item.getUri();
        if (uri != null) {
            if (DragAndDropMgr.checkUserChange(mContext, dstFile, uri)) {
                return true;
            }
        }

        if (dstFile != null) {
            bRet = DragAndDropMgr.canDrop(mContext, clipData, dstFile);
            if (bRet) {
                //to handle DragAndDrop into shortcut, mapping ShortcutFileRecord to corresponding FolderTreeRecord
                if (dstFile.getStorageType().equals(FileRecord.StorageType.Shortcut)) {
                    //initialized a FolderTreeRecord corresponding to the ShortcutFileRecord
                    dstFile = new FolderTreeRecord(dstFile.getFullPath());
                }
                DragAndDropMgr.convertDragItems(mFragment, mContext, this, clipData, dstFile);
            }
        }
        return bRet;
    }

    protected FileRecord getDstFile(int dropPosition) {
        FileRecord dstFile = null;
        NavigationManager naviMgr = NavigationManager.getInstance(mFragment.getProcessId());
        if (dropPosition == AppConstants.UNDEFINED) {
            NavigationInfo curInfo = naviMgr.getCurInfo();
            if (curInfo != null) {
                dstFile = curInfo.getCurRecord();
            }
        } else {
            dstFile = mListViewImp.getFileRecord(dropPosition);
            if (dstFile != null && !dstFile.isDirectory()) {
                dstFile = dstFile.getParent();
            }
        }
        return dstFile;
    }

    protected FileRecord getSelectFolder(int position) {
        FileRecord dstFile = null;
        if (position != AppConstants.UNDEFINED) {
            FileRecord fileRecord = mListViewImp.getFileRecord(position);
            if (fileRecord != null && fileRecord.isDirectory()) {
                dstFile = fileRecord;
            }
        }
        return dstFile;
    }

    @Override
    public void onProgressChanged(String fileName, int progress, int total) {
    }

    @Override
    public void onFinished(boolean bRet, String msg, Bundle extras) {
        if (!bRet && extras != null && extras.getInt(FileOperator.SIDESYNC_BUNDLE) != 1) {
            Toast.makeText(mContext, msg, Toast.LENGTH_LONG).show();
        }
        MyFilesFacade.execSpinnerProgress(mFragment.mProcessId, mContext, SpinnerProgressCmd.OperationProgress.DISMISS);
    }

    protected void ensureCurrentItemBackground(View view) {
        PreferenceUtils.ViewAsKey viewAsKey = getViewAsKey();
        if (view != null) {
            switch (PreferenceUtils.getViewAs(mContext, viewAsKey)) {
                case AppConstants.ViewType.LIST:
                case AppConstants.ViewType.LIST_DETAIL:
                case AppConstants.ViewType.TABLET_GRID_LARGE:
                case AppConstants.ViewType.TABLET_GRID_SMALL:
                    view.setBackgroundResource(UiUtils.getSelectableItemBackground(mContext));
                    break;
            }
        }
    }

    protected void restoreLastItemBackground(View prevView) {
        PreferenceUtils.ViewAsKey keyOpt = getViewAsKey();
        if (prevView != null) {
            switch (PreferenceUtils.getViewAs(mContext, keyOpt)) {
                case AppConstants.ViewType.LIST:
                case AppConstants.ViewType.LIST_DETAIL:
                case AppConstants.ViewType.TABLET_GRID_LARGE:
                case AppConstants.ViewType.TABLET_GRID_SMALL:
                    prevView.setBackground(null);
                    break;
            }
        }
    }

    private PreferenceUtils.ViewAsKey getViewAsKey() {
        NavigationManager naviMgr = NavigationManager.getInstance(mFragment.getProcessId());
        return PreferenceUtils.getViewAsKey(naviMgr.getCurInfo());
    }

    private class DragUpdateThread extends Thread {
        private final int DELAY_TIME_TO_SHOW_POINTER_GUIDE = 100;
        private final int COUNT_TIMES_DELAY = 5;
        private boolean mAlive;
        private boolean mIsShowGuide;
        private int mPosition;

        DragUpdateThread(int position, boolean isShowGuide, boolean alive) {
            mPosition = position;
            mIsShowGuide = isShowGuide;
            mAlive = alive;
        }

        void setAlive(boolean alive) {
            mAlive = alive;
        }

        @Override
        public void run() {
            try {
                FileRecord dstFiles = getSelectFolder(mPosition);
                if (mIsPointerGuideEnable) {
                    updateDragAndDropView(false, dstFiles);
                    mDragView.updateDragShadow(sShadowBuilder);
                    mIsPointerGuideEnable = false;
                }

                int count = 0;
                while (count < COUNT_TIMES_DELAY) {
                    count = count + 1;
                    Thread.sleep(DELAY_TIME_TO_SHOW_POINTER_GUIDE);
                    if (!mAlive || dstFiles == null || !mIsShowGuide || mDragView == null || mDragAndDropView == null) {
                        Log.d(this, "Return DragUpdateThread mAlive: " + mAlive + " mIsGuide: " + mIsShowGuide);
                        return;
                    }
                }

                updateDragAndDropView(true, dstFiles);
                mDragView.updateDragShadow(sShadowBuilder);
                mIsPointerGuideEnable = true;
            } catch (InterruptedException e) {
                Log.e(this, e.toString());
            }
        }
    }
}
